package org.gitee.simpleutil.util;


import cn.hutool.core.util.ObjectUtil;
import org.gitee.simpleutil.pojo.InterestVO;
import org.gitee.simpleutil.pojo.LoanPlanInfoVO;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;

/**
 * 等额本息计算工具
 *
 * @author lihonglin
 * @date 2025/5/14 16:14
 */
public class EqualPrincipalInterestUtil {

    private static final BigDecimal NUM_12 = new BigDecimal("12");
    private static final BigDecimal NUM_100 = new BigDecimal("100");
    private static final BigDecimal NUM_360 = new BigDecimal("360");
    //计算过程中保留小数
    private static final int SCALE = 4;
    private static final int SCALE_2 = 2;
    //计算过程中
    private static final RoundingMode MODE = RoundingMode.DOWN;
    //针对结果
    private static final int RESULT_SCALE = 0;
    private static final RoundingMode RESULT_MODE = RoundingMode.CEILING;

    public static void main(String[] args) {
        InterestVO interestVO = new InterestVO();
        interestMathUtil(interestVO);
    }

    public static List<LoanPlanInfoVO> interestMathUtil(InterestVO interestVO) {
        BigDecimal invest = new BigDecimal("1100");
        BigDecimal yearRate = new BigDecimal("0.12");
        BigDecimal financingYearRate = new BigDecimal("0.12");
        Integer periodsNum = 3;
        Integer financingPeriodsNum = 3;
        boolean isFinan = true;
        //日利率 * 当月天数 = 月利率
        BigDecimal dayRate = yearRate.divide(NUM_360, SCALE, MODE);
        BigDecimal monthRate = yearRate.divide(NUM_12, SCALE, MODE);
        //日融担费计算-当综合年化利率超出时，就会有融担费
        BigDecimal dayfinancingRate = financingYearRate.divide(NUM_360, SCALE, MODE);
        BigDecimal dayfinancingMonthRate = financingYearRate.divide(NUM_12, SCALE, MODE);
        BigDecimal perMonthPrincipalInterest = getPerMonthPrincipalInterest(invest, periodsNum, monthRate);
        invest = invest.setScale(SCALE_2, MODE);
        LocalDate date = LocalDate.now();
        LocalDate temp = ObjectUtil.clone(date);
        LocalDate nexMonDate = getNexMonDate(date);
        BigDecimal tempInvest = ObjectUtil.clone(invest).setScale(SCALE_2, MODE);
        BigDecimal count = new BigDecimal("0");
        //总融担费
        BigDecimal countFinancing = new BigDecimal("0");
        List<LoanPlanInfoVO> list = new ArrayList<>();
        for (int i = 1; i < periodsNum + 1; i++) {
            LoanPlanInfoVO vo = new LoanPlanInfoVO();
            //借款金额
            vo.setLoanAmt(tempInvest);
            //状态为正常
            vo.setRepayStatus("normal");
            //第几期
            vo.setPeriodsNum(i);
            //这两个字段暂时不用
            vo.setOverdueDays(0);
            vo.setFinancingRate(BigDecimal.ZERO);
            vo.setPunishInterestRate(BigDecimal.ZERO);
            vo.setPayableFinancingAmt(BigDecimal.ZERO);
            //日利率,年利率
            vo.setDayRate(dayRate);
            vo.setYearRate(yearRate);
            //月利率计算
            long days = Math.abs(ChronoUnit.DAYS.between(temp, nexMonDate));
            monthRate = dayRate.multiply(new BigDecimal(days));
            //当月利息
            BigDecimal monthInterest = invest.multiply(monthRate).setScale(SCALE_2, MODE);
            BigDecimal monthFinancing = BigDecimal.ZERO;
            //如果有融担费，需要计算
            if (isFinan) {
                dayfinancingMonthRate = dayfinancingRate.multiply(new BigDecimal(days));
                //当月融担费
                monthFinancing = invest.multiply(dayfinancingMonthRate).setScale(SCALE_2, MODE);
            }
            //月应还款利息
            vo.setPayableInterestAmt(monthInterest);
            if (i < periodsNum) {
                //每月本金
                BigDecimal principalAmt = perMonthPrincipalInterest.subtract(monthInterest).setScale(SCALE_2, MODE);
                System.out.println("等额本息---" + i + "--月还款本金:" + principalAmt + ",还款利息:" + monthInterest + ",融担费:" + monthFinancing);
                invest = invest.subtract(principalAmt);
                //月应还款本金
                vo.setPayablePrincipalAmt(principalAmt);
                //剩余本金
                vo.setSurplusPrincipalAmt(invest);
                //当月应还金额 本+息+融担
                vo.setPayableAmt(principalAmt.add(monthInterest).add(monthFinancing).setScale(SCALE_2, MODE));
            } else {
                System.out.println("等额本息---" + i + "--月还款本金:" + invest + ",还款利息:" + monthInterest + ",融担费:" + monthFinancing);
                //月应还款本金
                vo.setPayablePrincipalAmt(invest);
                //剩余本金
                vo.setSurplusPrincipalAmt(BigDecimal.ZERO);
                //当月应还金额 本+息+融担
                vo.setPayableAmt(invest.add(monthInterest).add(monthFinancing).setScale(SCALE_2, MODE));
            }
            //总利息
            count = count.add(monthInterest);
            //总融担费
            countFinancing = countFinancing.add(monthFinancing);
            list.add(vo);
        }
        //总应还金额 = 总融担费 + 所有本息
        BigDecimal totalDueAmt = countFinancing.add(tempInvest).add(count).setScale(SCALE_2, MODE);
        list.forEach(vo -> vo.setTotalPayableAmt(totalDueAmt));
        //分摊融担费，如果有融担费，需要计算
        BigDecimal finanFee = countFinancing.divide(new BigDecimal(financingPeriodsNum), SCALE_2, MODE);
        for (LoanPlanInfoVO vo : list) {
            if (vo.getPeriodsNum() <= financingPeriodsNum) {
                //应还融担费
                vo.setPayableFinancingAmt(finanFee.setScale(SCALE_2, MODE));
                //当月应还金额（本金+利息+融担）
                vo.setPayableAmt(vo.getPayableAmt().add(finanFee).setScale(SCALE, MODE));
                System.out.println("融担分期：融担日期：" + vo.getPayableDate() + "共：" + finanFee);
            }
        }
        System.out.println("总利息-保留小数：" + count);
        System.out.println("总利息-向上取整：" + count.setScale(RESULT_SCALE, RESULT_MODE));

        System.out.println("总融担-保留小数：" + countFinancing);
        System.out.println("总融担-向上取整：" + countFinancing.setScale(RESULT_SCALE, RESULT_MODE));
        return list;
    }

    public static BigDecimal getPerMonthPrincipalInterest(BigDecimal invest, int totalMonth, BigDecimal monthRate) {
        BigDecimal onePlusRate = BigDecimal.ONE.add(monthRate);
        double a = onePlusRate.doubleValue();
        double pow = Math.pow(a, totalMonth);
        BigDecimal v = invest.multiply((monthRate.multiply(BigDecimal.valueOf(pow))));
        BigDecimal z = BigDecimal.valueOf(Math.pow(BigDecimal.ONE.add(monthRate).doubleValue(), totalMonth) - 1);
        BigDecimal perMonthPrincipalInterest = v.divide(z, SCALE_2, MODE);
        return perMonthPrincipalInterest;
    }

    public static LocalDate getNexMonDate(LocalDate now) {
        int dayOfMonth = now.getDayOfMonth();
        //计算下一个还款日
        LocalDate nexMonDate = null;
        //对日还款
        if (dayOfMonth > 25) {
            //还款日-固定为25号
            nexMonDate = nexDate(now, now.getMonthValue() + 1, 25);
        } else {
            nexMonDate = now.plusMonths(1);
        }
        return nexMonDate;
    }

    private static LocalDate nexDate(LocalDate now, int dayOfMonth, int monthPlus) {
        int year = now.getYear();
        if (monthPlus > 12) {
            return LocalDate.of(year + 1, monthPlus - 12, dayOfMonth);
        }
        return LocalDate.of(year, monthPlus, dayOfMonth);
    }
}